{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "toc-hr-collapsed": false
   },
   "source": [
    "# 数据容器"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "ename": "IndexError",
     "evalue": "list assignment index out of range",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mIndexError\u001b[0m                                Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-1-269e7a3e91b3>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[0mx\u001b[0m \u001b[1;33m=\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[0mx\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;36m12\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m      3\u001b[0m \u001b[0mx\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mIndexError\u001b[0m: list assignment index out of range"
     ]
    }
   ],
   "source": [
    "x =[]\n",
    "x[0]=12\n",
    "x\n",
    "#python里面list是不能这么改变值的。js里面好像是可以的。\n",
    "#x.append(12)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在 Python 中，有个**数据容器**（Container） 的概念。\n",
    "\n",
    "其中包括**字符串**、由 `range()` 函数生成的**等差数列**、**列表**（List）、**元组**（Tuple）、**集合**（Set）、**字典**（Dictionary）。\n",
    "\n",
    "这些容器，各有各的用处。其中又分为_可变_容器（Mutable） 和_不可变_容器（Immutable）。可变的有列表、集合、字典；不可变的有字符串、`range()` 生成的等差数列元组。集合，又分为 *Set* 和 *Frozen Set*；其中，Set 是*可变的*，Frozen Set 是*不可变的*。\n",
    "\n",
    "字符串、由 `range()` 函数生成的等差数列、列表、元组是**有序类型**（Sequence Type），而集合与字典是_无序_的。\n",
    "\n",
    "![](images/python-containers-final.png)\n",
    "\n",
    "另外，集合没有_重合_元素。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 迭代（Iterate）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "数据容器里的元素是可以被**迭代的**（Iterable），它们其中包含的元素，可以被逐个访问，以便被处理。\n",
    "\n",
    "对于数据容器，有一个操作符，`in`，用来判断某个元素是否属于某个容器。\n",
    "\n",
    "由于数据容器的可迭代性，再加上这个操作符 `in`，在 Python 语言里写循环格外容易且方便（以字符串这个字符的容器作为例子）："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "P\n",
      "y\n",
      "t\n",
      "h\n",
      "o\n",
      "n\n"
     ]
    }
   ],
   "source": [
    "for c in 'Python':\n",
    "  print(c)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在 Python 出现之前，想要完成这样一个访问字符串中的每一个字符的循环，大抵上应该是这样的（比如 C 语言）：\n",
    "\n",
    "``` C\n",
    "# Written in C\n",
    "char *string;\n",
    "\n",
    "scanf(\"%s\",string); \n",
    "int i=strlen(string);\n",
    "int k = 0;\n",
    "while(k<i){    \n",
    "      printf(\"%c\", string[k]);\n",
    "      k++;    \n",
    "  }\n",
    " ```\n",
    " \n",
    " 在 Python 中，简单的 for 循环，只需要指定一个次数就可以了，因为有 range() 这个函数："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n",
      "1\n",
      "2\n",
      "3\n",
      "4\n",
      "5\n",
      "6\n",
      "7\n",
      "8\n",
      "9\n"
     ]
    }
   ],
   "source": [
    "for i in range(10):\n",
    "  print(i)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "即便是用比 C 更为“现代”一点的语言，也大抵上应该是这样的：\n",
    "\n",
    "```c\n",
    "var i;\n",
    "for (i = 0; i < 10; i++) { \n",
    "  console.log（i）\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "当然，有时候我们也需要比较复杂的计数器，不过，Python 也不只有 `for` 循环，还有 `while` 循环，在必要的时候可以写复杂的计数器。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "toc-hr-collapsed": true
   },
   "source": [
    "## 列表（List）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "列表和字符串一样，是个*有序类型*（Sequence Type）的容器，其中包含着有索引编号的元素。\n",
    "\n",
    "列表中的元素可以是不同类型。不过，在解决现实问题的时候，我们总是倾向于创建由同一个类型的数据构成的列表。遇到由不同类型数据构成的列表，我们更可能做的是想办法把不同类型的数据分门别类地拆分出来，整理清楚 —— 这种工作甚至有个专门的名称与之关联：*数据清洗*。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 列表的生成"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "生成一个列表，有以下几种方法：\n",
    "\n",
    "\n",
    "```python\n",
    "a_list = []\n",
    "b_list = [1, 2, 3]\n",
    "list(), or list(literable)            # 这是 Type Casting\n",
    "(expression with x) for x in iterable\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1, 2, 'p', 'y', 't', 'h', 'o', 'n'] has a length of 8.\n",
      "[1, 2, 3, 4, 5, 6, 7, 8, 11] has a length of 9.\n",
      "[1, 2, 4, 8, 16, 32, 64, 128] has a length of 8.\n"
     ]
    }
   ],
   "source": [
    "a_list = []\n",
    "a_list.append(1)\n",
    "a_list.append(2)\n",
    "print(a_list, f'has a length of {len(a_list)}.')\n",
    "\n",
    "#range() 返回的不是 list，需要用 list() 转换，否则也没办法调用 .append()\n",
    "b_list = list(range(1, 9))\n",
    "b_list.append(11)\n",
    "print(b_list, f'has a length of {len(b_list)}.')\n",
    "\n",
    "\n",
    "c_list = [2**x for x in range(8)]\n",
    "print(c_list, f'has a length of {len(c_list)}.')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这最后一种方法颇为神奇：\n",
    "\n",
    "```python\n",
    "[2**x for x in range(8)]\n",
    "```\n",
    "\n",
    "这种做法，叫做 **[List Comprehension](https://docs.python.org/3.7/tutorial/datastructures.html#tut-listcomps)**。\n",
    "\n",
    "*Comprehend* 这个词的意思除了“理解”之外，还有另外一个意思，就是“包括、囊括” —— 这样的话，你就大概能理解这种做法为什么被称作 *List Comprehension* 了。中文翻译中，怎么翻译的都有，“列表生成器”、“列表生成式”等等，都挺好。但是，被翻译成“列表解析器”，就不太好了，给人的感觉是操作反了……\n",
    "\n",
    "List comprehension 可以嵌套使用 `for`，甚至可以加上条件 `if`。官方文档里有个例子，是用来把两个元素并不完全相同的两个列表去同后拼成一个列表（下面稍作了改写）：\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "a_list comprehands 10 random numbers: [98, 93, 84, 66, 58, 66, 9, 75, 11, 21]\n",
      "... and it has 5 even numbers: [98, 84, 66, 58, 66]\n"
     ]
    }
   ],
   "source": [
    "import random\n",
    "\n",
    "n = 10 \n",
    "\n",
    "# 生成一个 n 个元素的序列，每个元素是 1~100 之间的随机数\n",
    "a_list = [random.randrange(1, 100) for i in range(n)]\n",
    "print(f'a_list comprehands {len(a_list)} random numbers: {a_list}')\n",
    "\n",
    "# 从 a_list 里把偶数都挑出来\n",
    "b_list = [x for x in a_list if x % 2 == 0]\n",
    "print(f'... and it has {len(b_list)} even numbers: {b_list}')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 列表的操作符"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "列表的操作符和字符串一样，因为它们都是有序容器。列表的操作符有：\n",
    "\n",
    "> * 拼接：`+` （与字符串不一样的地方是，不能用空格了 `' '`；\n",
    "> * 复制：`*`\n",
    "> * 逻辑运算：`in` 和 `not in`，`<`、`<=`、`>`、`>=`、`!=`、`==`\n",
    "\n",
    "而后两个列表也和两个字符串一样，可以被比较，即，可以进行逻辑运算；比较方法也跟字符串一样，从两个列表各自的第一个元素开始逐个比较，“一旦决出胜负马上停止”："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from IPython.core.interactiveshell import InteractiveShell\n",
    "InteractiveShell.ast_node_interactivity = \"all\"\n",
    "\n",
    "a_list = [1, 2, 3]\n",
    "b_list = [4, 5, 6]\n",
    "c_list = a_list + b_list * 3\n",
    "c_list\n",
    "7 not in c_list\n",
    "a_list > b_list"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 根据索引提取列表元素"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "列表当然也可以根据索引操作，但，由于列表是可变序列，所以，不仅可以提取，还可以删除，甚至替换。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[77, 80, 86]\n",
      "[77, 80, 86, 'E', 'U', 'J', 77, 80, 86, 77, 80, 86]\n",
      "\n",
      "E\n",
      "[77, 80, 86, 'E', 'U', 'J', 77, 80, 86, 77, 80, 86]\n",
      "['J', 77, 80, 86, 77, 80, 86]\n",
      "[77, 80, 86]\n",
      "[86, 'E', 'U', 'J']\n",
      "\n",
      "[77, 80, 86, 'U', 'J', 77, 80, 86, 77, 80, 86]\n",
      "[77, 80, 86, 'U', 'J', 77, 80, 86]\n",
      "\n",
      "[77, 'a', 86, 2, 'J', 77, 80, 86]\n"
     ]
    }
   ],
   "source": [
    "import random\n",
    "n = 3 \n",
    "a_list = [random.randrange(65, 91) for i in range(n)]\n",
    "b_list = [chr(random.randrange(65, 91)) for i in range(n)]\n",
    "print(a_list)\n",
    "c_list = a_list + b_list + a_list * 2\n",
    "print(c_list)\n",
    "\n",
    "print()\n",
    "# 根据索引提取（Slicing）\n",
    "print(c_list[3])        # 返回索引值为 3 的元素值\n",
    "print(c_list[:])        # 相当于 a_list，返回整个列表\n",
    "print(c_list[5:])       # 从索引为 5 的值开始直到末尾\n",
    "print(c_list[:3])       # 从索引 0 开始，直到索引 3 之前（不包括 3）\n",
    "print(c_list[2:6])      # 从索引 2 开始，直到索引 6 之前（不包括 6） \n",
    "\n",
    "print()\n",
    "# 根据索引删除\n",
    "del c_list[3]\n",
    "print(c_list)           # del 是个命令，del a_list[3] 是一个语句；不能这么写： print(del a_list[3])\n",
    "del c_list[5:8]         \n",
    "print(c_list)\n",
    "\n",
    "print()\n",
    "# 根据索引替换\n",
    "c_list[1:5:2] = ['a', 2]  # s[start:stop:step] = t，跟 range 的三个参数类似；\n",
    "                         # len(t) = len([start:stop:step]) 必须为真\n",
    "print(c_list)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "需要注意的地方是：**列表**（List）是可变序列，而**字符串**（str）是不可变序列，所以，对字符串来说，虽然也可以根据索引提取，但没办法根据索引删除或者替换。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tho\n"
     ]
    },
    {
     "ename": "TypeError",
     "evalue": "'str' object doesn't support item deletion",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-7-0601326f9f8f>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0ms\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m'Python'\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;36m5\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      2\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ms\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0;32mdel\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ms\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m3\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m  \u001b[0;31m# 这一句会报错\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m: 'str' object doesn't support item deletion"
     ]
    }
   ],
   "source": [
    "s = 'Python'[2:5]\n",
    "print(s)\n",
    "del(s[3])  # 这一句会报错"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "之前提到过：\n",
    "\n",
    "> 字符串常量（String Literal）是不可变有序容器，所以，虽然字符串也有一些 Methods 可用，但，那些 Methods 都不改变它们自身，而是在操作后返回一个值给另外一个变量。\n",
    "\n",
    "而对于列表这种*可变容器*，我们可以对它进行操作，结果是*它本身被改变*了。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Python\n",
      "['P', 'y', 't', 'h', 'o', 'n']\n",
      "['P', 'y', 'h', 'o', 'n']\n"
     ]
    }
   ],
   "source": [
    "s = 'Python'\n",
    "L = list(s)\n",
    "print(s)\n",
    "print(L)\n",
    "del(L[2])\n",
    "print(L) # 用 del() 对 L 操作之后，L 本身少了 1 个元素"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 列表可用的内建函数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "列表和字符串都是容器，它们可使用的内建函数也其实都是一样的：\n",
    "\n",
    "> * `len()`\n",
    "> * `max()`\n",
    "> * `min()`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[66, 70, 72]\n",
      "['Q', 'W', 'G']\n",
      "[66, 70, 72, 'Q', 'W', 'G', 66, 70, 72, 66, 70, 72]\n",
      "[66, 70, 72, 66, 70, 72, 66, 70, 72]\n",
      "12\n",
      "W\n",
      "G\n",
      "True\n"
     ]
    }
   ],
   "source": [
    "import random\n",
    "n = 3 \n",
    "\n",
    "# 生成 3 个随机数，构成一个列表\"\n",
    "a_list = [random.randrange(65, 91) for i in range(n)]\n",
    "b_list = [chr(random.randrange(65, 91)) for i in range(n)]\n",
    "print(a_list)\n",
    "print(b_list)\n",
    "\n",
    "# 列表可以使用操作符 + 和 *\n",
    "c_list = a_list + b_list + a_list * 2\n",
    "print(c_list)\n",
    "\n",
    "a_list *= 3\n",
    "print(a_list)\n",
    "\n",
    "# 内建函数操作 len()、max（）、min\n",
    "print(len(c_list))\n",
    "print(max(b_list)) # 内建函数内部做了异常处理，可以比较字符和数字 —— 初学者最讨厌这种事情了……\n",
    "print(min(b_list))\n",
    "\n",
    "print('X' not in b_list)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Methods"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "字符串常量和 range() 都是不可变的（Imutable）；而列表则是**可变类型**（Mutable type），所以，它最起码可以被排序 —— 使用 `sort()` Method："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "a_list comprehands 10 random numbers:\n",
      " [78, 49, 36, 68, 99, 99, 47, 56, 73, 21]\n",
      "the list sorted:\n",
      " [21, 36, 47, 49, 56, 68, 73, 78, 99, 99]\n",
      "the list sorted reversely:\n",
      " [99, 99, 78, 73, 68, 56, 49, 47, 36, 21]\n"
     ]
    }
   ],
   "source": [
    "import random\n",
    "n = 10 \n",
    "a_list = [random.randrange(1, 100) for i in range(n)]\n",
    "print(f'a_list comprehands {len(a_list)} random numbers:\\n', a_list)\n",
    "\n",
    "a_list.sort()\n",
    "print('the list sorted:\\n', a_list)\n",
    "\n",
    "a_list.sort(reverse=True) #reverse 参数，默认是 False\n",
    "print('the list sorted reversely:\\n', a_list)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如果列表中的元素全都是由字符串构成的，当然也可以排序："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "a_list comprehands 10 random string elements:\n",
      " ['O', 'W', 'Z', 'I', 'R', 'H', 'G', 'L', 'W', 'L']\n",
      "the list sorted:\n",
      " ['G', 'H', 'I', 'L', 'L', 'O', 'R', 'W', 'W', 'Z']\n",
      "the list sorted reversely:\n",
      " ['Z', 'W', 'W', 'R', 'O', 'L', 'L', 'I', 'H', 'G']\n",
      "\n",
      "b_list comprehands 10 random string elements:\n",
      " ['Ax', 'Uh', 'Gg', 'Co', 'Zh', 'Wi', 'Di', 'Is', 'Hu', 'Br']\n",
      "the sorted:\n",
      " ['Ax', 'Br', 'Co', 'Di', 'Gg', 'Hu', 'Is', 'Uh', 'Wi', 'Zh']\n",
      "the sorted reversely:\n",
      " ['Zh', 'Wi', 'Uh', 'Is', 'Hu', 'Gg', 'Di', 'Co', 'Br', 'Ax']\n"
     ]
    }
   ],
   "source": [
    "import random\n",
    "n = 10 \n",
    "\n",
    "a_list = [chr(random.randrange(65, 91)) for i in range(n)]\n",
    "# chr() 函数会返回指定 ascii 码的字符，ord('A') 是 65\n",
    "print(f'a_list comprehands {len(a_list)} random string elements:\\n', a_list)\n",
    "\n",
    "a_list.sort()\n",
    "print('the list sorted:\\n', a_list)\n",
    "\n",
    "a_list.sort(reverse=True) #reverse 参数，默认是 False\n",
    "print('the list sorted reversely:\\n', a_list)\n",
    "\n",
    "print()\n",
    "\n",
    "b_list = [chr(random.randrange(65, 91)) +\\\n",
    "            chr(random.randrange(97, 123))\\\n",
    "            for i in range(n)]\n",
    "# 可以在行末加上 \\ 符号，表示“该行未完待续……”\n",
    "\n",
    "print(f'b_list comprehands {len(b_list)} random string elements:\\n', b_list)\n",
    "\n",
    "b_list.sort()\n",
    "print('the sorted:\\n', b_list)\n",
    "\n",
    "b_list.sort(key=str.lower, reverse=True) \n",
    "# key 参数，默认是 None\n",
    "# key=str.lower 的意思是，在比较的时候，先全都转换成小写再比较……\n",
    "# —— 但并不改变原有值\n",
    "print('the sorted reversely:\\n', b_list)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**注意**：不能乱比较…… 被比较的元素应该是同一类型 —— 所以，不是由同一种数据类型元素构成的列表，不能使用 `sort()` Method。下面的代码会报错："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "'<' not supported between instances of 'str' and 'int'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-12-acb9480a455d>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0ma_list\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'a'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'c'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0ma_list\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0ma_list\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msort\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# 这一句会报错\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m: '<' not supported between instances of 'str' and 'int'"
     ]
    }
   ],
   "source": [
    "a_list = [1, 'a', 'c']\n",
    "a_list = a_list.sort() # 这一句会报错"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**可变序列**还有一系列可用的 **Methods**：`a.append()`，`a.clear()`，`a.copy()`，`a.extend(t)`，`a.insert(i， x)`，`a.pop([i])`， `a.remove(x)`， `a.reverse()`……"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[65, 66, 68]\n",
      "[65, 66, 68, 'C', 'T', 'Y', 65, 66, 68, 65, 66, 68]\n",
      "[65, 66, 68, 'C', 'T', 'Y', 65, 66, 68, 65, 66, 68, '100']\n",
      "\n",
      "[65, 66, 68]\n",
      "[]\n",
      "\n",
      "[65, 66, 68, 'C', 'T', 'Y', 65, 66, 68, 65, 66, 68, '100']\n",
      "[65, 66, 68, 'C', 'T', 'Y', 68, 65, 66, 68, '100']\n",
      "[65, 66, 68, 'C', 'T', 'Y', 65, 66, 68, 65, 66, 68, '100']\n",
      "\n",
      "[65, 66, 68, 'C', 'T', 'Y', 66, 68, '100']\n",
      "[65, 66, 68, 'C', 'T', 'Y', 66, 68, '100']\n",
      "\n",
      "[]\n",
      "[65, 66, 68, 'C', 'T', 'Y', 65, 66, 68, 65, 66, 68, '100']\n",
      "\n",
      "[65, 66, 68, 'C', 'T', 'Y', 65, 66, 68, 65, 66, 68, '100']\n",
      "[65, 'example', 66, 'example', 68, 'C', 'T', 'Y', 65, 66, 68, 65, 66, 68, '100']\n",
      "\n",
      "[65, 'example', 66, 'example', 68, 'C', 'T', 'Y', 65, 66, 68, 65, 66, 68, '100']\n",
      "['100', 68, 66, 65, 68, 66, 65, 'Y', 'T', 'C', 68, 'example', 66, 'example', 65]\n",
      "None\n"
     ]
    }
   ],
   "source": [
    "import random\n",
    "n = 3 \n",
    "a_list = [random.randrange(65, 91) for i in range(n)]\n",
    "b_list = [chr(random.randrange(65, 91)) for i in range(n)]\n",
    "print(a_list)\n",
    "c_list = a_list + b_list + a_list * 2\n",
    "print(c_list)\n",
    "\n",
    "# 在末尾追加一个元素\n",
    "c_list.append('100')\n",
    "print(c_list)\n",
    "\n",
    "# 清空序列\n",
    "print()\n",
    "print(a_list)\n",
    "a_list.clear()\n",
    "print(a_list)\n",
    "\n",
    "print()\n",
    "# 拷贝一个列表\n",
    "d_list = c_list.copy()\n",
    "print(d_list)\n",
    "del(d_list[6:8])\n",
    "print(d_list)\n",
    "print(c_list)             # 对一个拷贝操作，不会更改“原件”\n",
    "\n",
    "print()\n",
    "# 演示拷贝 .copy() 与赋值 = 的不同\n",
    "e_list = d_list\n",
    "del(e_list[6:8])\n",
    "print(e_list)\n",
    "print(d_list)             # 对 e_list 操作，相等于对 d_list 操作\n",
    "\n",
    "# 在末尾追加一个列表\n",
    "print()\n",
    "print(a_list)\n",
    "a_list.extend(c_list)      # 相当于 a_list =+ c_list\n",
    "print(a_list)\n",
    "\n",
    "# 在某索引位置插入一个元素\n",
    "print()\n",
    "print(a_list)\n",
    "a_list.insert(1, 'example')   # 在索引 1 的位置插入 'example'\n",
    "a_list.insert(3, 'example')   # 在索引 3 的位置插入 'example'；\n",
    "print(a_list)\n",
    "\n",
    "# 排序\n",
    "\n",
    "# a_list.sort() 这一句会出错，因为当前列表中的元素，是 int 和 str 混合的。\n",
    "\n",
    "print()\n",
    "print(a_list)\n",
    "a_list.reverse()\n",
    "print(a_list)\n",
    "x = a_list.reverse() # reverse() 只对当前序列操作，并不返回一个逆序列表；返回值是 None\n",
    "print(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "有一个函数、两个 Methods 与删除单个元素相关联， `del()`，`a.pop[i]`，`a.remove(x)`  ，请注意它们之间的区别。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[86, 69, 81]\n",
      "\n",
      "\n",
      "[86, 'example', 69, 81]\n",
      "[86, 69, 81]\n",
      "\n",
      "[86, 69, 81]\n",
      "[86, 69]\n",
      "81\n",
      "\n",
      "[86, 69, 'example', 'example']\n",
      "[86, 69, 'example']\n",
      "\n",
      "None\n",
      "[86, 69]\n"
     ]
    }
   ],
   "source": [
    "import random\n",
    "n = 3 \n",
    "a_list = [random.randrange(65, 91) for i in range(n)]\n",
    "print(a_list)\n",
    "\n",
    "# 插入\n",
    "print()\n",
    "a_list.insert(1, 'example')   # 在索引 1 的位置插入 'example'\n",
    "\n",
    "# 删除\n",
    "print()\n",
    "print(a_list)\n",
    "a_list.remove('example')      # 去除 'example' 这个元素，如果有多个 'example'，只删除第一个\n",
    "print(a_list)\n",
    "\n",
    "# pop() 删除并返回被删除的值\n",
    "\n",
    "print()\n",
    "print(a_list)\n",
    "p = a_list.pop(2)      # 去除索引为 2 的元素，且返回元素的值，赋值给 p\n",
    "print(a_list)\n",
    "print(p)\n",
    "\n",
    "# pop() 与 del()，或者 remove() 的区别\n",
    "print()\n",
    "a_list.insert(2, 'example')\n",
    "a_list.insert(2, 'example')\n",
    "print(a_list)\n",
    "del(a_list[2])\n",
    "print(a_list)\n",
    "\n",
    "print()\n",
    "print(a_list.remove('example')) # a_list.remove() 这个方法的返回值是 None\n",
    "print(a_list)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 小结"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "看起来是个新概念，例子全部读完也很是要花上一段时间，然而，从操作上来看，操作列表和操作字符串的差异并不大，重点在于一个是 Immutable，另外一个是 Mutable，所以，例如像 `a.sort()`，`a.remove()` 这样的事儿，列表能做，字符串不能做 —— 字符串也可以排序，但，那是排序之后返回给另外一个变量；而列表可以直接改变自身……\n",
    "\n",
    "而整理成表格之后呢，理解与记忆真的是零压力：\n",
    "\n",
    "![](images/list-concepts.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 元组（Tuple）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在完整掌握列表的创建与操作之后，再理解元组（Tuple） 就容易了，因为它们之间的主要区别只有两个：\n",
    "\n",
    "> * List 是*可变*有序容器，Tuple 是*不可变*有序容器。\n",
    "> * List 用*方括号*标识 `[]`，Tuple 用*圆括号* 标识`()`；\n",
    "\n",
    "创建一个元组的时候，用圆括号：\n",
    "\n",
    "```python\n",
    "a = ()\n",
    "``` \n",
    "\n",
    "这样就创建了一个空元组。\n",
    "\n",
    "多个元素之间，用 `,` 分离。\n",
    "\n",
    "创建一个含多个元素的元组，可以省略这个括号。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(1, 2, 3)\n",
      "(1, 2, 3)\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = 1, 2, 3   # 不建议这种写法\n",
    "b = (1, 2, 3) # 在创建元组的时候建议永远不省略圆括号……\n",
    "print(a)\n",
    "print(b)\n",
    "a == b"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**注意**：创建单个元素的元组，无论是否使用圆括号，在那唯一的元素后面一定要*补上一个逗号* `,`："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(2,)"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "2"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "2"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "int"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "(2,)"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from IPython.core.interactiveshell import InteractiveShell\n",
    "InteractiveShell.ast_node_interactivity = \"all\"\n",
    "\n",
    "a = 2, # 注意这个末尾的逗号 , 它使得 a 变量被定义为一个元组，而不是数字\n",
    "a\n",
    "\n",
    "b = 2  # 整数，赋值\n",
    "b\n",
    "\n",
    "c = (2) # 不是元组\n",
    "c\n",
    "type(c) # 还是 int\n",
    "\n",
    "d = (2,) # 这才是元组\n",
    "d\n",
    "a == d"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "元组是不可变序列，所以，你没办法从里面删除元素。\n",
    "\n",
    "但是，你可以在末尾追加元素。所以，严格意义上，对元组来讲，“不可变”的意思是说，“**当前已有部分不可变**”……"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(1,)\n",
      "4339120112\n",
      "(1, 3, 5)\n",
      "4338763312\n"
     ]
    }
   ],
   "source": [
    "a = 1, \n",
    "print(a)\n",
    "print(id(a))\n",
    "a += 3, 5\n",
    "print(a)\n",
    "print(id(a)) # id 并不相同 —— 实际上是在内存中另外新创建了一个元组…… "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "初学者总是很好奇 List 和 Tuple 的区别。首先是使用场景，在将来需要更改的时候，创建 List\n",
    "；在将来不需要更改的时候，创建 Tuple。其次，从计算机的角度来看，Tuple 相对于 List 占用更小的内存。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "48"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "80024"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "90088"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from IPython.core.interactiveshell import InteractiveShell\n",
    "InteractiveShell.ast_node_interactivity = \"all\"\n",
    "\n",
    "n = 10000 #@param {type:\"number\"}\n",
    "a = range(n)\n",
    "b = tuple(a) # 把 a 转换成元组\n",
    "c = list(a) # 把 a 转换成列表\n",
    "a.__sizeof__()\n",
    "b.__sizeof__()\n",
    "c.__sizeof__()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "等你了解了 Tuple 的标注方法，你就会发现，`range()` 函数返回的等差数列就是一个 Tuple —— `range(6)` 就相当于 `(0, 1, 2, 3, 4, 5)`。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "toc-hr-collapsed": true
   },
   "source": [
    "## 集合（Set）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**集合**（Set）这个容器类型与列表不同的地方在于，首先它*不包含重合元素*，其次它是*无序*的；进而，集合又分为两种，Set，*可变的*，Frozen Set，*不可变的*。\n",
    "\n",
    "创建一个集合，用**花括号** `{}` 把元素括起来，用 `,` 把元素隔开："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{2, 3, 5, 7, 11, 13, 17}\n"
     ]
    }
   ],
   "source": [
    "primes = {2, 3, 5, 7, 11, 13, 17}\n",
    "primes\n",
    "print(primes)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "toc-hr-collapsed": true
   },
   "source": [
    "### 创建"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "注意：创建空集合的时候，必须用 `set()`，而不能用 `{}`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "dict"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "set"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from IPython.core.interactiveshell import InteractiveShell\n",
    "InteractiveShell.ast_node_interactivity = \"all\"\n",
    "\n",
    "a = {} # 注意这样创建的是一个 dict（字典），而不是 set 集合\n",
    "b = set() # 这样创建的才是空集合\n",
    "type(a)\n",
    "type(b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "也可以将序列数据转换（Casting） 为集合。转换后，返回的是一个已**去重**的集合。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'a', 'b', 'c', 'd', 'e', 'f'}"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "{1, 2, 3}"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "{'a', 'b', 'e'}"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from IPython.core.interactiveshell import InteractiveShell\n",
    "InteractiveShell.ast_node_interactivity = \"all\"\n",
    "\n",
    "a = \"abcabcdeabcdbcdef\"\n",
    "b = range(10)\n",
    "c = [1, 2, 2, 3, 3, 1]\n",
    "d = ('a', 'b', 'e', 'b', 'a')\n",
    "set(a)\n",
    "set(b)\n",
    "set(c)\n",
    "set(d)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Set 当然也可以进行 *Comprehension*："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'d', 'e', 'f'}"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = \"abcabcdeabcdbcdef\"\n",
    "b = {x for x in a if x not in 'abc'}\n",
    "b"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 操作"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "将序列类型数据转换成 Set，就等于**去重**。当然，也可以用 `in` 来判断某个元素是否属于这个集合。`copy()`、`len()`、`max()`、`min()`，也都可以用来操作 Set，但 `del()` 却不行 —— 因为 Set 中的元素没有索引（它不是有序容器）。从 Set 里删除元素，得用 `set.remove(elem)` 方法；而 Frozen Set 是不可变的，所以不能用 `set.remove(elem)` 方法操作。\n",
    "\n",
    "对于集合，有相应的操作符对它们可以进行集合运算：\n",
    "\n",
    "> * 并集： `|`\n",
    "> * 交集： `&`\n",
    "> * 差集： `-`\n",
    "> * 对称差集： `^`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "之前用 `set('abcabcdeabcdbcdef')` 作为简单例子还凑合能用；但，这样对读者无意义的集合，无助于进一步的理解。\n",
    "\n",
    "事实上，每种数据结构（Data Structures —— 在这一章里，我们一直用的概念是“容器”，其实是指同一事物的两种称呼）都有自己的应用场景。比如，当我们需要管理很多用户时，集合就可以派上很大用场。\n",
    "\n",
    "假定两个集合中有些人是 admins，所有人都是 moderators：\n",
    "\n",
    "```python\n",
    "admins = {'Moose', 'Joker', 'Joker'}\n",
    "moderators = {'Ann', 'Chris', 'Jane', 'Moose', 'Zero'}\n",
    "```\n",
    "\n",
    "那么："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'Joker', 'Moose'}"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "{'Ann', 'Chris', 'Jane', 'Joker', 'Moose', 'Zero'}"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "{'Moose'}"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "{'Joker'}"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "{'Ann', 'Chris', 'Jane', 'Joker', 'Zero'}"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "admins = {'Moose', 'Joker', 'Joker'}\n",
    "moderators = {'Ann', 'Chris', 'Jane', 'Moose', 'Zero'}\n",
    "\n",
    "admins                 # 去重自动完成\n",
    "'Joker' in admins      # Joker 是否是 admins？\n",
    "'Joker' in moderators  # Joker 是否是 moderator？\n",
    "admins | moderators    # admins、 moderator，或者身兼两职的，即，两个角色中的所有人 in admins or moderators or both\n",
    "admins & moderators    # 既是 admins 又是 moderator 的都有谁？ in both admins and moderators\n",
    "admins - moderators    # 是 admins 但不是 moderator 的都有谁？ in admins but not in moderators\n",
    "admins ^ moderators    # admins 和 moderator 中不是身兼两职的都有谁？in admins or users but not both"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 这个 cell 集合运算图示需要安装 matplotlib 和 matplotlib-venn\n",
    "# !pip install matplotlib\n",
    "# !pip install matplotlib-venn\n",
    "import matplotlib.pyplot as plt\n",
    "from matplotlib_venn import venn2\n",
    "\n",
    "admins = {'Moose', 'Joker', 'Joker'}\n",
    "moderators = {'Ann', 'Chris', 'Jane', 'Moose', 'Zero'}\n",
    "\n",
    "v = venn2(subsets = (admins, moderators), set_labels =('admins', 'moderators'))\n",
    "v.get_label_by_id('11').set_text('\\n'.join(admins&moderators))\n",
    "v.get_label_by_id('10').set_text('\\n'.join(admins-moderators))\n",
    "v.get_label_by_id('01').set_text('\\n'.join(admins^moderators))\n",
    "\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "以上的操作符，都有另外一个版本，即，用 Set 这个类的方法完成。\n",
    "\n",
    "|   意义    | 操作符 | 方法                    | 方法相当于 |\n",
    "| :------: | :----: | :---------------------: | :--: |\n",
    "| 并集     | `\\|`    | `set.union(*others)`         | `set \\| other \\| ...` |\n",
    "| 交集     | `&`    | `set.intersection(*others)` | `set & other & ...` |\n",
    "| 差集     | `-`    | `set.difference(*others)` | `set - other - ...` |\n",
    "| 对称差集 | `^`    | `set.symmetric_difference(other)` | `set ^ other` |\n",
    "\n",
    "注意，并集、交集、差集的方法，可以接收多个集合作为参数 `(*other)`，但对称差集方法只接收一个参数 `(other)`。\n",
    "\n",
    "对于集合，推荐更多使用方法而不是操作符的主要原因是：更易读 —— 对人来说，因为有意义、有用处的代码终将需要人去维护。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'Chris', 'Jane', 'Joker', 'Moose', 'Zero'}"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "{'Moose'}"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "{'Joker'}"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "{'Chris', 'Jane', 'Joker', 'Zero'}"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from IPython.core.interactiveshell import InteractiveShell\n",
    "InteractiveShell.ast_node_interactivity = \"all\"\n",
    "\n",
    "admins = {'Moose', 'Joker', 'Joker'}\n",
    "moderators = {'Chris', 'Moose', 'Jane', 'Zero'}\n",
    "\n",
    "admins.union(moderators)\n",
    "admins.intersection(moderators)\n",
    "admins.difference(moderators)\n",
    "admins.symmetric_difference(moderators)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 逻辑运算"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "两个集合之间可以进行逻辑比较，返回布尔值。\n",
    "\n",
    "**set** `==` **other**\n",
    "> `True`: set 与 other 相同\n",
    "\n",
    "**set** `!=` **other**\n",
    "> `True`: set 与 other 不同\n",
    "\n",
    "**isdisjoint**(_other_)\n",
    "> `True`: set 与 other 非重合；即，`set & other == None`\n",
    "\n",
    "**issubset**(_other_)，**set** `<=` **other**\n",
    "> `True`: set 是 other 的子集\n",
    "\n",
    "**set** `<` **other**\n",
    "> `True`: set 是 other 的真子集，相当于 `set <= other && set != other`\n",
    "\n",
    "**issuperset**(_other_)，**set** `>=` **other**\n",
    "> `True`: set 是 other 的超集\n",
    "\n",
    "**set** `>` **other**\n",
    "> `True`: set 是 other 的真超集，相当于 `set >= other && set != other`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "toc-hr-collapsed": true
   },
   "source": [
    "### 更新"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "对于集合，有以下更新它自身的方法："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**add**(*elem*)\n",
    "> 把 elem 加入集合\n",
    "\n",
    "**remove**(*elem*)\n",
    "> 从集合中删除 elem；如果集合中不包含该 elem，会产生 KeyError 错误。\n",
    "\n",
    "**discard**(*elem*)\n",
    "> 如果该元素存在于集合中，删除它。\n",
    "\n",
    "**pop**(*elem*)\n",
    "> 从集合中删除 elem，并返回 elem 的值，针对空集合做此操作会产生 KeyEroor 错误。\n",
    "\n",
    "**clear**()\n",
    "从集合中删除所有元素。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**set.update**(*_others_) ，相当于 `set |= other | ...`\n",
    "> 更新 set, 加入 others 中的所有元素；\n",
    "\n",
    "**set.intersection_update**(*_others_)，相当于 `set &= other & ...`\n",
    "> 更新 set, 保留同时存在于 set 和所有 others 之中的元素；\n",
    "\n",
    "**set.difference_update**(*_others_)，相当于 `set -= other | ...`\n",
    "> 更新 set, 删除所有在 others 中存在的元素；\n",
    "\n",
    "**set.symmetric_difference_update**(_other_)，相当于 `set ^= other`\n",
    "> 更新 set, 只保留存在于 set 或 other 中的元素，但不保留同时存在于 set 和 other 中的元素；**注意**，该方法*只接收一个参数*。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 冻结集合"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "还有一种集合，叫做冻结集合（Frozen Set），Frozen Set 之于 Set，正如 Tuple 之于 List，前者是不可变容器（Immutable），后者是可变容器（Mutable），无非是为了节省内存使用而设计的类别。\n",
    "\n",
    "有空去看看这个链接就可以了：\n",
    "\n",
    "> https://docs.python.org/3/library/stdtypes.html#frozenset"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "toc-hr-collapsed": true
   },
   "source": [
    "## 字典（Dictionary）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Map 是容器中的单独一类，**映射**（Map）容器。映射容器只有一种，叫做**字典**（Dictionary）。先看一个例子："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'ann': 6575, 'bob': 8982, 'joe': 2598, 'zoe': 1225}"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "phonebook = {'ann':6575, 'bob':8982, 'joe':2598, 'zoe':1225}\n",
    "phonebook"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "字典里的每个元素，由两部分组成，_key_（键）和 _value_（值），二者由一个冒号连接。\n",
    "\n",
    "比如，`'ann':6575` 这个字典元素，_key_ 是 `'ann'`，_value_ 是 `6575`。\n",
    "\n",
    "字典直接使用 _key_ 作为索引，并映射到与它匹配的 _value_："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "8982"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "phonebook = {'ann':6575, 'bob':8982, 'joe':2598, 'zoe':1225}\n",
    "phonebook['bob']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在同一个字典里，_key_ 都是唯一的。当创建字典的时候，如果其中有重复的 _key_ 的话，就跟 Set 那样会“**自动去重**” —— 保留的是众多重复的 _key_ 中的最后一个 _key:value_（或者说，最后一个 _key:value_ “之前那个 _key_ 的 _value_ 被**更新**了”。字典这个数据类型之所以叫做 Map（映射），是因为字典里的 _key_ 都映射且只映射一个对应的 _value_。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'ann': 6585, 'bob': 8982, 'joe': 2598, 'zoe': 1225}"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "phonebook = {'ann':6575, 'bob':8982, 'joe':2598, 'zoe':1225, 'ann':6585}\n",
    "phonebook"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在已经了解如何操作列表之后，再去理解字典的操作，其实没什么难度，无非就是字典多了几个 Methods。\n",
    "\n",
    "提蓄一下自己的耐心，把下面的若干行代码都仔细阅读一下，猜一猜输出结果都是什么？"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 字典的生成"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{}"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "{'a': 1, 'b': 2, 'c': 3}"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from IPython.core.interactiveshell import InteractiveShell\n",
    "InteractiveShell.ast_node_interactivity = \"all\"\n",
    "\n",
    "aDict = {}\n",
    "bDict = {'a':1, 'b':2, 'c':3}\n",
    "aDict\n",
    "bDict"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 更新某个元素"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2598"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "{'ann': 6585, 'bob': 8982, 'joe': 5802, 'zoe': 1225}"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "5802"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from IPython.core.interactiveshell import InteractiveShell\n",
    "InteractiveShell.ast_node_interactivity = \"all\"\n",
    "\n",
    "phonebook1 = {'ann':6575, 'bob':8982, 'joe':2598, 'zoe':1225, 'ann':6585}\n",
    "\n",
    "phonebook1['joe']\n",
    "phonebook1['joe'] = 5802\n",
    "phonebook1\n",
    "phonebook1['joe']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 添加元素"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'ann': 6585,\n",
       " 'bob': 8982,\n",
       " 'joe': 2598,\n",
       " 'zoe': 1225,\n",
       " 'john': 9876,\n",
       " 'mike': 5603,\n",
       " 'stan': 6898,\n",
       " 'eric': 7898}"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from IPython.core.interactiveshell import InteractiveShell\n",
    "InteractiveShell.ast_node_interactivity = \"all\"\n",
    "\n",
    "phonebook1 = {'ann':6575, 'bob':8982, 'joe':2598, 'zoe':1225, 'ann':6585}\n",
    "phonebook2 = {'john':9876, 'mike':5603, 'stan':6898, 'eric':7898}\n",
    "\n",
    "phonebook1.update(phonebook2)\n",
    "phonebook1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 删除某个元素"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'bob': 8982, 'joe': 2598, 'zoe': 1225}"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from IPython.core.interactiveshell import InteractiveShell\n",
    "InteractiveShell.ast_node_interactivity = \"all\"\n",
    "\n",
    "phonebook1 = {'ann':6575, 'bob':8982, 'joe':2598, 'zoe':1225, 'ann':6585}\n",
    "\n",
    "del(phonebook1['ann'])\n",
    "phonebook1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 逻辑操作符"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "dict_keys(['ann', 'bob', 'joe', 'zoe'])"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "dict_values([6585, 8982, 2598, 1225])"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "dict_items([('ann', 6585), ('bob', 8982), ('joe', 2598), ('zoe', 1225)])"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "phonebook1 = {'ann':6575, 'bob':8982, 'joe':2598, 'zoe':1225, 'ann':6585}\n",
    "\n",
    "'ann' in phonebook1\n",
    "\n",
    "phonebook1.keys()\n",
    "'stan' in phonebook1.keys()\n",
    "\n",
    "phonebook1.values()\n",
    "1225 in phonebook1.values()\n",
    "\n",
    "phonebook1.items()\n",
    "('stan', 6898) in phonebook1.items()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 可用来操作的内建函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "8"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "'zoe'"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "'ann'"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "['ann', 'bob', 'joe', 'zoe', 'john', 'mike', 'stan', 'eric']"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "('ann', 'bob', 'joe', 'zoe', 'john', 'mike', 'stan', 'eric')"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "{'ann', 'bob', 'eric', 'joe', 'john', 'mike', 'stan', 'zoe'}"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "['ann', 'bob', 'eric', 'joe', 'john', 'mike', 'stan', 'zoe']"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "['zoe', 'stan', 'mike', 'john', 'joe', 'eric', 'bob', 'ann']"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from IPython.core.interactiveshell import InteractiveShell\n",
    "InteractiveShell.ast_node_interactivity = \"all\"\n",
    "\n",
    "phonebook1 = {'ann':6575, 'bob':8982, 'joe':2598, 'zoe':1225, 'ann':6585}\n",
    "phonebook2 = {'john':9876, 'mike':5603, 'stan':6898, 'eric':7898}\n",
    "phonebook1.update(phonebook2)\n",
    "\n",
    "len(phonebook1)\n",
    "max(phonebook1)\n",
    "min(phonebook1)\n",
    "list(phonebook1)\n",
    "tuple(phonebook1)\n",
    "set(phonebook1)\n",
    "sorted(phonebook1)\n",
    "sorted(phonebook1, reverse=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 常用 Methods"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'john': 9876, 'mike': 5603, 'stan': 6898, 'eric': 7898}"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "{}"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "{'john': 9876, 'mike': 5603, 'stan': 6898, 'eric': 7898}"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "('zoe', 1225)"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "{'ann': 6585, 'bob': 8982, 'joe': 2598}"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "3538"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "{'ann': 6585, 'bob': 8982, 'joe': 2598}"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "3538"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "{'ann': 6585, 'bob': 8982, 'joe': 2598}"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "3538"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "{'ann': 6585, 'bob': 8982, 'joe': 2598, 'adam': 3538}"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from IPython.core.interactiveshell import InteractiveShell\n",
    "InteractiveShell.ast_node_interactivity = \"all\"\n",
    "\n",
    "phonebook1 = {'ann':6575, 'bob':8982, 'joe':2598, 'zoe':1225, 'ann':6585}\n",
    "phonebook2 = {'john':9876, 'mike':5603, 'stan':6898, 'eric':7898}\n",
    "\n",
    "phonebook3 = phonebook2.copy()\n",
    "phonebook3\n",
    "\n",
    "phonebook3.clear()\n",
    "phonebook3\n",
    "\n",
    "phonebook2                      # .copy() 的“原件”不会发生变化\n",
    "\n",
    "p = phonebook1.popitem()\n",
    "p\n",
    "phonebook1\n",
    "\n",
    "p = phonebook1.pop('adam', 3538)\n",
    "p\n",
    "phonebook1\n",
    "\n",
    "p = phonebook1.get('adam', 3538)\n",
    "p\n",
    "phonebook1\n",
    "\n",
    "p = phonebook1.setdefault('adam', 3538)\n",
    "p\n",
    "phonebook1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "toc-hr-collapsed": true
   },
   "source": [
    "## 迭代各种容器中元素"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "我们总是有这样的需求：对容器中的元素逐一进行处理（运算）。这样的时候，我们就用 `for` 循环去迭代它们。\n",
    "\n",
    "对于迭代 `range()` 和 `list` 中的元素我们已经很习惯了："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n",
      "1\n",
      "2\n"
     ]
    }
   ],
   "source": [
    "for i in range(3):\n",
    "    print(i)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "2\n",
      "3\n"
     ]
    }
   ],
   "source": [
    "for i in [1, 2, 3]:\n",
    "    print(i)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 迭代的同时获取索引"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "有时，我们想同时得到有序容器中的元素及其索引，那么可以调用 `enumerate()` 函数来帮我们："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0 P\n",
      "1 y\n",
      "2 t\n",
      "3 h\n",
      "4 o\n",
      "5 n\n"
     ]
    }
   ],
   "source": [
    "s = 'Python'\n",
    "for i, c in enumerate(s):\n",
    "    print(i, c)\n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0 0\n",
      "1 1\n",
      "2 2\n"
     ]
    }
   ],
   "source": [
    "for i, v in enumerate(range(3)):\n",
    "    print(i, v)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0 ann\n",
      "1 bob\n",
      "2 joe\n",
      "3 john\n",
      "4 mike\n"
     ]
    }
   ],
   "source": [
    "L = ['ann', 'bob', 'joe', 'john', 'mike']\n",
    "for i, L in enumerate(L):\n",
    "    print(i, L)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0 ann\n",
      "1 bob\n",
      "2 joe\n",
      "3 john\n",
      "4 mike\n"
     ]
    }
   ],
   "source": [
    "t = ('ann', 'bob', 'joe', 'john', 'mike')\n",
    "for i, t in enumerate(t):\n",
    "    print(i, t)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 迭代前排序"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "可以用 `sorted()` 和 `reversed()` 在迭代前先排好序："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0 ann\n",
      "1 bob\n",
      "2 joe\n",
      "3 john\n",
      "4 mike\n"
     ]
    }
   ],
   "source": [
    "t = ('bob', 'ann', 'john', 'mike', 'joe')\n",
    "for i, t in enumerate(sorted(t)):\n",
    "    print(i, t)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0 mike\n",
      "1 john\n",
      "2 joe\n",
      "3 bob\n",
      "4 ann\n"
     ]
    }
   ],
   "source": [
    "t = ('bob', 'ann', 'john', 'mike', 'joe')\n",
    "for i, t in enumerate(sorted(t, reverse=True)):\n",
    "    print(i, t)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0 joe\n",
      "1 mike\n",
      "2 john\n",
      "3 ann\n",
      "4 bob\n"
     ]
    }
   ],
   "source": [
    "t = ('bob', 'ann', 'john', 'mike', 'joe')\n",
    "for i, t in enumerate(reversed(t)):\n",
    "    print(i, t)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 同时迭代多个容器"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "可以在 `zip()` 这个函数的帮助下，同时迭代两个或者两个以上的容器中的元素（这样做的前提是，多个容器中的元素数量最好相同）："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Let's assume a represents 1.\n",
      "Let's assume b represents 2.\n",
      "Let's assume c represents 3.\n",
      "Let's assume d represents 4.\n",
      "Let's assume e represents 5.\n",
      "Let's assume f represents 6.\n",
      "Let's assume g represents 7.\n",
      "Let's assume h represents 8.\n",
      "Let's assume i represents 9.\n",
      "Let's assume j represents 10.\n",
      "Let's assume k represents 11.\n",
      "Let's assume l represents 12.\n",
      "Let's assume m represents 13.\n",
      "Let's assume n represents 14.\n",
      "Let's assume o represents 15.\n",
      "Let's assume p represents 16.\n",
      "Let's assume q represents 17.\n",
      "Let's assume r represents 18.\n",
      "Let's assume s represents 19.\n",
      "Let's assume t represents 20.\n",
      "Let's assume u represents 21.\n",
      "Let's assume v represents 22.\n",
      "Let's assume w represents 23.\n",
      "Let's assume x represents 24.\n",
      "Let's assume y represents 25.\n",
      "Let's assume z represents 26.\n"
     ]
    }
   ],
   "source": [
    "chars='abcdefghijklmnopqrstuvwxyz'\n",
    "nums=range(1, 27)\n",
    "for c, n in zip(chars, nums):\n",
    "    print(f\"Let's assume {c} represents {n}.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 迭代字典中的元素"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "ann 6585\n",
      "bob 8982\n",
      "joe 2598\n",
      "zoe 1225\n"
     ]
    }
   ],
   "source": [
    "phonebook1 = {'ann':6575, 'bob':8982, 'joe':2598, 'zoe':1225, 'ann':6585}\n",
    "\n",
    "for key in phonebook1:\n",
    "    print(key, phonebook1[key])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "ann 6585\n",
      "bob 8982\n",
      "joe 2598\n",
      "zoe 1225\n"
     ]
    }
   ],
   "source": [
    "phonebook1 = {'ann':6575, 'bob':8982, 'joe':2598, 'zoe':1225, 'ann':6585}\n",
    "\n",
    "for key, value in phonebook1.items():\n",
    "    print(key, value)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 总结"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这一章的内容，只不过是“多”而已，一旦逻辑关系理顺，就会觉得很简单。而这一章的开头，已经是最好的总结了。\n",
    "\n",
    "最后需要补充的，只是两个参考链接，以后有什么搞不明白的地方，去那里翻翻就能找到答案：\n",
    "\n",
    "> * https://docs.python.org/3/tutorial/datastructures.html#dictionaries\n",
    "> * https://docs.python.org/3/library/stdtypes.html#typesmapping"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.0"
  },
  "toc-autonumbering": true
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
